/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef PANDA_PLUGINS_ETS_ARKTS_HEADER_HEADER_WRITER_H_
#define PANDA_PLUGINS_ETS_ARKTS_HEADER_HEADER_WRITER_H_

#include <iostream>
#include <cstdint>
#include <cerrno>

#include <vector>
#include "libpandafile/file.h"
#include "libpandafile/class_data_accessor-inl.h"
#include "plugins/ets/runtime/types/ets_type.h"

namespace panda::ets::header_writer {

class HeaderWriter {
public:
    explicit HeaderWriter(std::unique_ptr<const panda_file::File> &&input, std::string output);

    void CreateHeader()
    {
        OpenOutput();
        if (!output_file_.is_open()) {
            LOG(FATAL, ETS_NAPI) << "Cannot create file '" << output_name_ << "'";
            exit(1);
        }
        PrintBegin();
    }

    void OpenOutput();

    bool PrintBegin()
    {
        output_file_ << "/* DO NOT EDIT, file is autogenerated */\n"
                     << "#include <ets_napi.h>\n\n"
                     << "#ifdef __cplusplus\n"
                     << "extern \"C\" {\n"
                     << "#endif\n\n";
        return true;
    }

    bool PrintFunction();

    bool CheckOverloading(panda_file::ClassDataAccessor &cda, panda_file::MethodDataAccessor &mda);

    void PrintPrototype(const std::string &class_name, panda_file::MethodDataAccessor &mda, bool is_overloaded);

    void ProcessProtoType(panda_file::Type type, panda_file::File::EntityId klass, std::string &sign,
                          std::string &args);

    bool PrintEnd()
    {
        output_file_ << "#ifdef __cplusplus\n"
                     << "}\n"
                     << "#endif\n";
        return true;
    }

    void CloseOutput()
    {
        if (output_file_.is_open()) {
            output_file_.close();
        }
    }

private:
    std::unique_ptr<const panda_file::File> input_file_;
    std::string output_name_;
    std::ofstream output_file_;
    bool need_header_ = false;
};

}  // namespace panda::ets::header_writer

#endif  // PANDA_PLUGINS_ETS_ARKTS_HEADER_HEADER_WRITER_H_
